package com.ideaaedi.commonspring.listener;

import com.ideaaedi.commonspring.entity.dto.RateLimitInfoDTO;
import com.ideaaedi.commonspring.event.RateLimitValidateEvent;
import com.ideaaedi.commonspring.lite.ratelimiter.RateLimiter;
import jakarta.annotation.Resource;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationListener;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * 限流异常
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2100.10.17.LTS17
 */
public class DefaultRateLimiterExpireListener implements ApplicationListener<RateLimitValidateEvent> {

    public static final String BEAN_NAME = "rateLimiterExpireListener";

    @Resource
    private RedissonClient redissonClient;

    private final long expireDuration;

    public DefaultRateLimiterExpireListener(long expireDuration) {
        this.expireDuration = expireDuration;
    }

    @Override
    public void onApplicationEvent(RateLimitValidateEvent event) {
        RateLimitInfoDTO rateLimitInfo = event.getRateLimitInfo();
        boolean obtainedToken = rateLimitInfo.isObtainedToken();
        // 未获取到令牌，则不处理
        if (!obtainedToken) {
            return;
        }
        String rateLimiterUid = rateLimitInfo.getRateLimiterUid();
        RateLimiter rateLimiterAnno = rateLimitInfo.getRateLimiterAnno();
        long interval = rateLimiterAnno.interval();
        TimeUnit intervalUnit = rateLimiterAnno.intervalUnit();
        // redis键过期时长设置为： 时间窗口时长 + expireDuration秒
        long currExpireDuration = intervalUnit.toMillis(interval) + TimeUnit.SECONDS.toMillis(expireDuration);
        // 限流配置过期时长
        RBucket<Object> bucket = redissonClient.getBucket(rateLimiterUid);
        if (bucket != null) {
            bucket.expire(Duration.ofMillis(currExpireDuration));
        }
        // 限流实时数据过期时长
        bucket = redissonClient.getBucket(rateLimiterUid + ":permits");
        if (bucket != null) {
            bucket.expire(Duration.ofMillis(currExpireDuration));
        }
        bucket = redissonClient.getBucket(rateLimiterUid + ":value");
        if (bucket != null) {
            bucket.expire(Duration.ofMillis(currExpireDuration));
        }
    }
}
